﻿using System;
using System.Xml.Linq;

namespace SharePoint.Orm.Caml {
	///<summary>
	/// A value as in &lt;Value Type=""Text""&gt;Completed&lt;/Value&t;
	///</summary>
	public class CamlValue {
		/// <summary>
		/// The type of value (e.g. Text).
		/// </summary>
		public CamlValueType Type { get; set; }
		
		/// <summary>
		/// The value of the type (e.g. CamlTextValue or CamlCurrentUser).
		/// </summary>
		public CamlValueChild ValueChild { get; set; }

		///<summary>
		/// Don't use this.  Instead use new CamlTextValue("value").
		///</summary>
		[Obsolete]
		public string Value {
			get {
				return ValueChild == null ? null : ValueChild.ToXml().ToString();
			}
			set {
				ValueChild = new CamlTextValue(value);
			}
		}

		///<summary>
		/// Converts a Type to a string.
		///</summary>
		public string GetTypeAsString() {
			switch (Type) {
				case CamlValueType.String:
					return "String";
				case CamlValueType.Text:
					return "Text";
				case CamlValueType.Integer:
					return "Integer";
				case CamlValueType.Counter:
					return "Counter";
				case CamlValueType.User:
					return "User";
                case CamlValueType.Number:
			        return "Number";
                case CamlValueType.DateTime:
			        return "DateTime";
                case CamlValueType.Computed:
			        return "Computed";
                case CamlValueType.Note:
			        return "Note";
                case CamlValueType.Lookup:
			        return "Lookup";
				default:
					throw new Exception("Unexpected type '" + Type + "'");
			}
		}

		///<summary>
		/// Using this syntax you should specify Type and CamlChild using object initialization syntax.
		///</summary>
		public CamlValue() {
		}

		///<summary>
		/// Convenience operator that initializes this object with a ValueChild of CamlText.
		///</summary>
		public CamlValue(CamlValueType type, string value) {
			Type = type;
			ValueChild = new CamlTextValue(value);
		}

		///<summary>
		/// Initializes this CamlValue with a ValueChild of CamlText.
		///</summary>
		public CamlValue(CamlValueType type, CamlValueChild value) {
			Type = type;
			ValueChild = value;
		}

		///<summary>
		/// Converts the CamlValue into XML.
		///</summary>
		public XElement ToXml() {
			XElement valueElement = new XElement("Value", new XAttribute("Type", GetTypeAsString()));
			if (ValueChild != null) {
				valueElement.Add(ValueChild.ToXml());
			}
			return valueElement;
		}

		///<summary>
		/// Parses xml into a CamlValue.
		///</summary>
		public static CamlValue Parse(XElement element) {
			XAttribute typeAttr = element.Attribute("Type");
			if (typeAttr == null) {
				throw new Exception("Value element requires a 'Type' attribute");
			}
			CamlValueType type = ParseType(typeAttr.Value);
			string value = element.Value;
			CamlValue result = new CamlValue(type, value);
			return result;
		}

		private static CamlValueType ParseType(string value) {
			return (CamlValueType)Enum.Parse(typeof(CamlValueType), value, true);
		}
	}
}
